/*
*    l3qd - Light, light, lightweight queue
*    Copyright (C) 2024  Marcus Pedersén marcus@marcux.org
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
	"notabug.org/marcux/l3q/cmd/l3q/cmd/add"
	"notabug.org/marcux/l3q/cmd/l3q/cmd/cancel"
	"notabug.org/marcux/l3q/cmd/l3q/cmd/list"
	"notabug.org/marcux/l3q/cmd/l3q/cmd/set"
	"notabug.org/marcux/l3q/cmd/l3q/cmd/show"
	"notabug.org/marcux/l3q/cmd/l3q/cmd/validate"
	"notabug.org/marcux/l3q/internal/client"
	"os"
	"os/user"
	"slices"
)

var rootCmdFlagLong bool
var rootCmdFlagVerbose bool

var rootCmd = &cobra.Command{
	Use:   "l3q",
	Short: "L3q - Client for the Light, light, lightweight queue system.",
	Long: `Description:
  L3q - Client for the light, light, lightweigt queue system.
  Queue system to run multiple processes on multiple nodes. 
  This is the client program for l3q that interacts with the l3q daemon.
  This tool is used to get status, add jobs and configure the current l3q system.
  If called without arguments the queue will be printed, same as: l3q list queue
  In l3q a job is a complete unit that is queued and executed as one unit.
  A task is one program that is executed as part of a job that contains multiple tasks.
  Tasks within a job can be executed in sequence or in parallel.

  Requires that config file either in $HOME/.l3q/l3q.conf
  or /etc/l3q/l3q.conf is configured with connection parameters
  to be able to communicate with the l3qd daemon.`,
	PersistentPreRun: func(cmd *cobra.Command, args []string) {
		conf := client.GetConfig(true)
		l3qGrp, err := user.LookupGroup(conf.L3qGroup)
		if err != nil {
			switch err.(type) {
			case user.UnknownGroupError:
				fmt.Fprintf(os.Stderr, "Group: %s, specified in config file does not exist.\n", conf.L3qGroup)
				os.Exit(1)
			default:
				fmt.Fprintf(os.Stderr, "Failed to get info for group: %s, specified in config file: %s\n", conf.L3qGroup, err)
				os.Exit(1)
			}
		}

		usr, err := user.Current()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to get current user: %s\n", err)
			os.Exit(1)
		}

		// User is root
		if usr.Uid == "0" {
			return
		}

		grps, err := usr.GroupIds()
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to get all groups for current user: %s, %s\n", usr.Name, err)
			os.Exit(1)
		}

		if !slices.Contains(grps, l3qGrp.Gid) {
			fmt.Fprintf(os.Stderr, "Permission denied\n")
			os.Exit(1)
		}
	},
	Run: func(cmd *cobra.Command, args []string) {
		list.PrintQueue(rootCmdFlagLong, rootCmdFlagVerbose, false, 0)
	},
}

func Execute() error {
	return rootCmd.Execute()
}

func init() {
	rootCmd.Flags().BoolVarP(&rootCmdFlagLong, "long", "l", false, "Print extended, long list.")
	rootCmd.Flags().BoolVarP(&rootCmdFlagVerbose, "verbose", "v", false, "Print verbose output")
	rootCmd.AddCommand(versionCmd)
	rootCmd.AddCommand(list.ListCmd)
	rootCmd.AddCommand(show.ShowCmd)
	rootCmd.AddCommand(set.SetCmd)
	rootCmd.AddCommand(cancel.CancelCmd)
	rootCmd.AddCommand(add.AddCmd)
	rootCmd.AddCommand(validate.ValidateCmd)
}
